package com.ev.report.service.impl;

import cn.afterturn.easypoi.entity.vo.TemplateExcelConstants;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.view.PoiBaseView;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.util.TypeUtils;
import com.ev.common.enums.AuditStatusDict;
import com.ev.custom.domain.DictionaryDO;
import com.ev.custom.domain.FacilityDO;
import com.ev.custom.domain.MaterielDO;
import com.ev.custom.service.DictionaryService;
import com.ev.custom.service.FacilityService;
import com.ev.custom.service.MaterielService;
import com.ev.framework.config.Constant;
import com.ev.framework.config.ConstantForMES;
import com.ev.framework.config.ConstantForReport;
import com.ev.framework.config.MyExcelExportStyleConfig;
import com.ev.framework.utils.*;
import com.ev.report.dao.WarehouseAccountingReportDao;
import com.ev.report.service.WarehouseAccountingReportService;
import com.ev.report.vo.*;
import com.ev.scm.domain.StockAgeSettingDO;
import com.ev.scm.domain.StockDO;
import com.ev.scm.service.StockAgeSettingService;
import com.ev.scm.service.StockAnalysisService;
import com.ev.scm.service.StockService;
import com.ev.scm.service.StockStartService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.ui.ModelMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WarehouseAccountingReportServiceImpl implements WarehouseAccountingReportService {
    @Autowired
    private WarehouseAccountingReportDao reportDao;
    @Autowired
    private StockAnalysisService stockAnalysisService;
    @Autowired
    private StockService stockService;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private FacilityService facilityService;
    @Autowired
    private MaterielService materielService;
    @Autowired
    private StockAgeSettingService stockAgeSettingService;
    @Autowired
    private StockStartService stockStartService;



    @Override
    public List<StockOutItemVO> stockOutItem(Map<String, Object> params) {
        return reportDao.stockOutItem(params);
    }

    @Override
    public List<StockInItemVO> stockInItem(Map<String, Object> params) {
        return reportDao.stockInItem(params);
    }

    @Override
    public List<InOutStockItemVO> inOutStockItem(Map<String, Object> params) {
        return reportDao.inOutStockItem(params);
    }

    @Override
    public List<Map<String, Object>> stockList(Map<String, Object> params) {
        return reportDao.stockList(params);
    }

    @Override
    public List<Map<String, Object>> pickingSummary(Map<String, Object> params) {
        return reportDao.pickingSummary(params);
    }

    @Override
    public Pair<List<Map<String, Object>>, Map<String, Object>> inOutSummaryResult(int showPeriodTotalInt, int showMaterielTotalInt, int showItemInt, String startTime, String endTime, Long materielType, Long materielId) {

        Map<String, Object> params = Maps.newHashMap();
        boolean showItem = showItemInt == 1;
        boolean showMaterielTotal = showMaterielTotalInt == 1;
        boolean showPeriodTotal = showPeriodTotalInt == 1;
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("materielId", materielId);
        params.put("materielType", materielType);
        List<Map<String, Object>> stockList = stockAnalysisService.listForMap(params);
        Map<String, Object> totalResult = stockAnalysisService.countForTotal(params);
        if (stockList.size() > 0) {
            List<Map<String, Object>> showList = Lists.newArrayList();

            List<String> periodList = stockList
                    .stream()
                    .map(e -> e.get("period").toString())
                    .distinct()
                    .collect(Collectors.toList());

            // 获取期间对应的秒数
            Map<String, Long> periodMap = stockList
                    .stream()
                    .collect(Collectors.toMap(k -> k.get("period").toString(),
                            v -> Long.parseLong(v.get("times").toString()), (v1, v2) -> v1));

            // 获取最大的一个物料ID
//            long maxMaterielId = Long.parseLong(materielIdMap
//                    .keySet()
//                    .stream()
//                    .max(Comparator.comparing(Long::parseLong))
//                    .orElse("0")
//            );
            long maxMaterielId = stockList
                    .stream()
                    .map(v->Long.parseLong(v.get("materielId").toString()))
                    .max(Comparator.comparing(v->v))
                    .orElse(0L);
            //  计算数量
            ArrayList<Map<String, Object>> cloneStockList = BeanUtils.clone((ArrayList<Map<String, Object>>) stockList);
            Map<String, Map<String, Map<String, Object>>> reduceMap = cloneStockList
                    .stream()
                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
                                    , v -> v,
                                    (v1, v2) -> {
                                        v1.put("initialCount", MathUtils.getBigDecimal(v1.get("initialCount")).add(MathUtils.getBigDecimal(v2.get("initialCount"))));
                                        v1.put("initialAmount", MathUtils.getBigDecimal(v1.get("initialAmount")).add(MathUtils.getBigDecimal(v2.get("initialAmount"))));
                                        v1.put("inCount", MathUtils.getBigDecimal(v1.get("inCount")).add(MathUtils.getBigDecimal(v2.get("inCount"))));
                                        v1.put("inAmount", MathUtils.getBigDecimal(v1.get("inAmount")).add(MathUtils.getBigDecimal(v2.get("inAmount"))));
                                        v1.put("outCount", MathUtils.getBigDecimal(v1.get("outCount")).add(MathUtils.getBigDecimal(v2.get("outCount"))));
                                        v1.put("outAmount", MathUtils.getBigDecimal(v1.get("outAmount")).add(MathUtils.getBigDecimal(v2.get("outAmount"))));
                                        v1.put("finalCount", MathUtils.getBigDecimal(v1.get("finalCount")).add(MathUtils.getBigDecimal(v2.get("finalCount"))));
                                        v1.put("finalAmount", MathUtils.getBigDecimal(v1.get("finalAmount")).add(MathUtils.getBigDecimal(v2.get("finalAmount"))));
                                        return v1;
                                    }
                            )));

//            // 期初数量
//            Map<String, Map<String, BigDecimal>> initialCountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("initialCount")),BigDecimal::add)
//                    ));
//
//            // 期初金额
//            Map<String, Map<String, BigDecimal>> initialAmountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("initialAmount")),BigDecimal::add)
//                    ));
//            // 本期入库数量
//            Map<String, Map<String, BigDecimal>> inCountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("inCount")),BigDecimal::add))
//                    );
//            // 入库金额
//            Map<String, Map<String, BigDecimal>> inAmountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("inAmount")),BigDecimal::add))
//                    );
//            // 本期出库数量
//            Map<String, Map<String, BigDecimal>> outCountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("outCount")),BigDecimal::add))
//                    );
//            // 出库金额
//            Map<String, Map<String, BigDecimal>> outAmountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("outAmount")),BigDecimal::add))
//                    );
//            // 结存数量
//            Map<String, Map<String, BigDecimal>> finalCountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("finalCount")),BigDecimal::add))
//                    );
//            // 结存金额
//            Map<String, Map<String, BigDecimal>> finalAmountMap = stockList
//                    .stream()
//                    .collect(Collectors.groupingBy(k1 -> k1.get("period").toString()
//                            , Collectors.toMap(k2 -> k2.get("materielId").toString()
//                                    , v -> MathUtils.getBigDecimal(v.get("finalAmount")),BigDecimal::add))
//                    );

            Map<String, Object> map;
//            Map<String, BigDecimal> initialCountForPeriod;
//            Map<String, BigDecimal> initialAmountForPeriod;
//            Map<String, BigDecimal> inCountForPeriod;
//            Map<String, BigDecimal> inAmountForPeriod;
//            Map<String, BigDecimal> outCountForPeriod;
//            Map<String, BigDecimal> outAmountForPeriod;
//            Map<String, BigDecimal> finalCountForPeriod;
//            Map<String, BigDecimal> finalAmountForPeriod;
            Map<String, Map<String, Object>> reduceCount;
            for (String periodParam : periodList) {
//                initialCountForPeriod = initialCountMap.get(periodParam);
//                initialAmountForPeriod = initialAmountMap.get(periodParam);
//                inCountForPeriod = inCountMap.get(periodParam);
//                inAmountForPeriod = inAmountMap.get(periodParam);
//                outCountForPeriod = outCountMap.get(periodParam);
//                outAmountForPeriod = outAmountMap.get(periodParam);
//                finalCountForPeriod = finalCountMap.get(periodParam);
//                finalAmountForPeriod = finalAmountMap.get(periodParam);
                reduceCount = reduceMap.get(periodParam);
                if (showMaterielTotal) {
                    for (String materielIdParam : reduceCount.keySet()) {
                        map = BeanUtils.clone((HashMap<String,Object>)reduceCount.get(materielIdParam));
//                      map = Maps.newHashMap(reduceCount.get(materielIdParam));
                        map.remove("batch");
                        map.put("materielId", materielIdParam);
                        // 标记颜色 1 为中间状态
                        map.put("sign", 1);
                        // 排序号
                        map.put("sortNo", 1);
                        map.put("period", periodParam.substring(0,7));
                        map.put("times", periodMap.get(periodParam));
                        map.put("materielName", map.getOrDefault("materielName","") + ConstantForReport.TOTAL_SUFFIX);
//                        map.put("initialCount", initialCountForPeriod.get(materielIdParam));
//                        map.put("initialAmount", initialAmountForPeriod.get(materielIdParam));
//                        map.put("inCount", inCountForPeriod.get(materielIdParam));
//                        map.put("inAmount", inAmountForPeriod.get(materielIdParam));
//                        map.put("outCount", outCountForPeriod.get(materielIdParam));
//                        map.put("outAmount", outAmountForPeriod.get(materielIdParam));
//                        map.put("finalCount", finalCountForPeriod.get(materielIdParam));
//                        map.put("finalAmount", finalAmountForPeriod.get(materielIdParam));
                        showList.add(map);
                    }
                }

                Map<String, Object> periodTotalMap;
                if (showPeriodTotal) {
                    reduceCount =  BeanUtils.clone((HashMap<String, Map<String, Object>>)reduceCount);

                    periodTotalMap = reduceCount
                            .values()
                            .stream()
                            .reduce((v1, v2) -> {
                                v1.put("initialCount", MathUtils.getBigDecimal(v1.get("initialCount")).add(MathUtils.getBigDecimal(v2.get("initialCount"))));
                                v1.put("initialAmount", MathUtils.getBigDecimal(v1.get("initialAmount")).add(MathUtils.getBigDecimal(v2.get("initialAmount"))));
                                v1.put("inCount", MathUtils.getBigDecimal(v1.get("inCount")).add(MathUtils.getBigDecimal(v2.get("inCount"))));
                                v1.put("inAmount", MathUtils.getBigDecimal(v1.get("inAmount")).add(MathUtils.getBigDecimal(v2.get("inAmount"))));
                                v1.put("outCount", MathUtils.getBigDecimal(v1.get("outCount")).add(MathUtils.getBigDecimal(v2.get("outCount"))));
                                v1.put("outAmount", MathUtils.getBigDecimal(v1.get("outAmount")).add(MathUtils.getBigDecimal(v2.get("outAmount"))));
                                v1.put("finalCount", MathUtils.getBigDecimal(v1.get("finalCount")).add(MathUtils.getBigDecimal(v2.get("finalCount"))));
                                v1.put("finalAmount", MathUtils.getBigDecimal(v1.get("finalAmount")).add(MathUtils.getBigDecimal(v2.get("finalAmount"))));
                                return v1;
                            }).orElse(Maps.newHashMap());
                    periodTotalMap.remove("batch");
                    periodTotalMap.remove("materielTypeName");
                    periodTotalMap.remove("materielSerialNo");
                    periodTotalMap.remove("materielName");
                    periodTotalMap.remove("specification");
                    periodTotalMap.remove("unitUomName");
                    periodTotalMap.put("materielId", maxMaterielId);
                    // 标记颜色 1 为中间状态
                    periodTotalMap.put("sign", ConstantForReport.COLOUR_END);
                    // 排序号
                    periodTotalMap.put("sortNo", 2);
                    periodTotalMap.put("period", periodParam.substring(0,7) + ConstantForReport.TOTAL_SUFFIX);
                    periodTotalMap.put("times", periodMap.get(periodParam));
//                    map.put("initialCount", initialCountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("initialAmount", initialAmountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("inCount", inCountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("inAmount", inAmountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("outCount", outCountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("outAmount", outAmountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("finalCount", finalCountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
//                    map.put("finalAmount", finalAmountForPeriod
//                            .values()
//                            .stream()
//                            .reduce(BigDecimal::add)
//                            .orElse(BigDecimal.ZERO));
                    showList.add(periodTotalMap);
                }

            }

            if (showItem) {
                showList.addAll(stockList);
            }

            List<Map<String, Object>> collect = showList.stream()
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())))
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("materielId").toString())))
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("times").toString())))
                    .collect(Collectors.toList());

            return Pair.of(collect,totalResult);

        }
        return null;
    }

    @Override
    public Pair<List<InOutStockItemVO>, Map<String, Object>> inOutStockItemResult(String startTimeParam, String endTimeParam, Long materielType, Long materielId) {
        Map<String, Object> params = Maps.newHashMap();
        Date startPeriod = DateFormatUtil.getDateByParttern(startTimeParam, DateFormatUtil.DATE_PATTERN_YMD);

        Date endPeriod = DateFormatUtil.getDateByParttern(endTimeParam, DateFormatUtil.DATE_PATTERN_YMD);

        if (materielId == null || endPeriod == null || startPeriod == null) {
            return null;
        }
        long statTimeLong = startPeriod.getTime();
        long endTimeLong = endPeriod.getTime();
        String startTime = DatesUtil.getSupportBeginDayOfMonth(startPeriod);
        String endTime = DatesUtil.getSupportEndDayOfMonth(endPeriod);
        params.put("materielType", materielType);
        params.put("materielId", materielId);

        params.put("auditSign", AuditStatusDict.OK_AUDIT.getId());

        Map<Long, Integer> accuracy = materielService.getAccuracy(Collections.singletonList(materielId)).get(0);
        Integer ac = accuracy.get(materielId);

        // 选择已关账的期间
//        params.put("isClose", 1);

        List<InOutStockItemVO> totalList = Lists.newArrayList();
        // 获取查询时间之前的期初数据动态计算
        // 期间数据(从核算表中取)
//        List<InOutStockItemVO> initData = this.getInitDataForItem(params);
        // 截至时间 计算查询开始前期初数据
        params.put("deadline", startTime);
        List<InOutStockItemVO> initData = this.getInitDataByStock(params);
        InOutStockItemVO inOutStockItemLast = null;
        if (initData.size() > 0) {
            inOutStockItemLast = initData.get(initData.size() - 1);
        }
//        List<String> periodInit = initData.stream().map(InOutStockItemVO::getPeriod).distinct().collect(Collectors.toList());
        // 明细数据
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        List<InOutStockItemVO> inOutStockItemVOS = this.inOutStockItem(params);
//        List<InOutStockItemVO> periodItem = inOutStockItemVOS.stream().filter(e->!periodInit.contains(e.getPeriod())).collect(Collectors.toList());

        // 存在未统计期间
        if (inOutStockItemVOS.size() > 0) {
            List<InOutStockItemVO> initListCopy = ListUtils.deepCopy(inOutStockItemVOS);
            if(initListCopy.get(0).getType()==1){
                initListCopy.get(0).setCount(initListCopy.get(0).getCount().negate());
            }
            // type ->0 入 1 出
            Map<String, Long> findOne = initListCopy.stream().collect(Collectors.groupingBy(InOutStockItemVO::getPeriod, Collectors.counting()));

            initListCopy.forEach(e->{
                Long aLong = findOne.get(e.getPeriod());
                if (aLong == 1L) {
                    boolean isOut = e.getType() == 1;
                    if (isOut) {
                        e.setOutCount(e.getCount());
                        e.setOutAmount(e.getAmount());
                    } else {
                        e.setInCount(e.getCount());
                        e.setInAmount(e.getAmount());
                    }
                }
            });
            Map<String, InOutStockItemVO> collect = initListCopy
                    .stream()
                    .collect(Collectors.toMap(InOutStockItemVO::getPeriod
                            , e -> e, (e1, e2) -> {
                                boolean isOut = e2.getType() == 1;
                                e1.setCount(e1.getCount().add(isOut?e2.getCount().negate():e2.getCount()));
                                e1.setAmount(e1.getAmount().add(isOut?e2.getAmount().negate():e2.getAmount()));
                                if (isOut){
                                    e1.setOutCount(e1.getCount());
                                    e1.setOutAmount(e1.getAmount());
                                }else {
                                    e1.setInCount(e1.getInCount());
                                    e1.setInAmount(e1.getInAmount());
                                }
                                return e1;
                            }));
            BigDecimal finalCount = BigDecimal.ZERO;
            BigDecimal finalAmount = BigDecimal.ZERO;
            if (inOutStockItemLast != null) {
                finalCount = inOutStockItemLast.getFinalCount();
                finalAmount = inOutStockItemLast.getFinalAmount();
            }
            List<InOutStockItemVO> collect1 = collect.values().stream().sorted(Comparator.comparing(InOutStockItemVO::getPeriod)).collect(Collectors.toList());

            for (InOutStockItemVO outStockItemVO : collect1) {
                BigDecimal outAmount = outStockItemVO.getOutAmount();
                outAmount = outAmount == null ? BigDecimal.ZERO : outAmount;
                BigDecimal outCount = outStockItemVO.getOutCount();
                outCount = outCount == null ? BigDecimal.ZERO : outCount;
                BigDecimal inCount = outStockItemVO.getInCount();
                inCount = inCount == null ? BigDecimal.ZERO : inCount;
                BigDecimal inAmount = outStockItemVO.getInAmount();
                inAmount = inAmount == null ? BigDecimal.ZERO : inAmount;

                outStockItemVO.setBalanceAmount(finalAmount.abs());
                outStockItemVO.setBalanceCount(finalCount.abs());

//                outStockItemVO.setBalanceAmount(finalAmount);
//                outStockItemVO.setBalanceCount(finalCount);

                if (finalCount.compareTo(BigDecimal.ZERO)==0){
                    outStockItemVO.setBalanceUnitPrice(BigDecimal.ZERO);
                }else {
                    // unitPrice
                    outStockItemVO.setBalanceUnitPrice(finalAmount.divide(finalCount,ac,BigDecimal.ROUND_HALF_UP));
                }
//                if (outCount.compareTo(BigDecimal.ZERO)==0){
//                    outStockItemVO.setOutUnitPrice(BigDecimal.ZERO);
//                }else {
//                    outStockItemVO.setOutUnitPrice(outAmount.divide(outCount,Constant.BIGDECIMAL_ZERO,BigDecimal.ROUND_HALF_UP));
//                }
//                if (inCount.compareTo(BigDecimal.ZERO)==0){
//                    outStockItemVO.setInUnitPrice(BigDecimal.ZERO);
//                }else {
//                    outStockItemVO.setInUnitPrice(inAmount.divide(inCount,Constant.BIGDECIMAL_ZERO,BigDecimal.ROUND_HALF_UP));
//                }
                finalAmount = inAmount.add(finalAmount).subtract(outAmount);
                finalCount = inCount.add(finalCount).subtract(outCount);
                outStockItemVO.setTimes(DatesUtil.getSupportBeginDayOfMonthToDate(outStockItemVO.getInOutTime()).getTime()/1000);
                outStockItemVO.setInOutTime(null);
                outStockItemVO.setOutCount(null);
                outStockItemVO.setOutAmount(null);
                outStockItemVO.setType(null);
                outStockItemVO.setBatch(null);
                outStockItemVO.setCode(null);
                outStockItemVO.setSortNo(0);

                outStockItemVO.setStorageTypeName("期初结存");
            }
//            initData.addAll(collect1);
            totalList.addAll(collect1);
        }

//        initData.forEach(e -> e.setBalanceUnitPrice(e.getBalanceCount().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : e.getBalanceAmount().divide(e.getBalanceCount(), Constant.BIGDECIMAL_ZERO, BigDecimal.ROUND_HALF_UP)));
//        totalList.addAll(initData);

//        Map<String, InOutStockItemVO> initialMap = initData.stream()
//                .collect(Collectors.toMap(InOutStockItemVO::getPeriod
//                        , v -> v));

        Map<String, InOutStockItemVO> periodForVO = totalList
                .stream()
                .collect(Collectors.toMap(InOutStockItemVO::getPeriod, v -> v));

        Map<String, List<InOutStockItemVO>> groupByPeriod = inOutStockItemVOS
                .stream()
                .collect(Collectors.groupingBy(InOutStockItemVO::getPeriod));
        List<InOutStockItemVO> groupByStockVOS;
        BigDecimal initialCount;
        BigDecimal initialAmount;
        // 计算
        BigDecimal newInitialUnitPrice;
        // 出入库
        BigDecimal count;
        BigDecimal amount;
        BigDecimal unitPrice;
        // 判断是否为出库
        boolean isOut;
        // 合计行
        InOutStockItemVO inOutStockItemVO;
        InOutStockItemVO  initMap;
        for (String period : periodForVO.keySet()) {
            initMap = periodForVO.get(period);
            // 期初数量
            initialCount = initMap.getBalanceCount();
            // 期初金额
            initialAmount = initMap.getBalanceAmount();

            groupByStockVOS = groupByPeriod.get(period);
            if (groupByStockVOS !=null && groupByStockVOS.size()>0) {
                // 将数据按时间升序排列
                groupByStockVOS.sort(Comparator.comparing(InOutStockItemVO::getInOutTime));

                for (InOutStockItemVO groupByStockVO : groupByStockVOS) {
                    isOut = groupByStockVO.getType() == 1;
                    count = groupByStockVO.getCount();
                    amount = groupByStockVO.getAmount();
                    unitPrice = groupByStockVO.getUnitPrice();
                    if (isOut) {
                        initialCount = initialCount.subtract(count) ;
                        initialAmount = initialAmount.subtract(amount) ;
                        groupByStockVO.setOutUnitPrice(unitPrice);
                        groupByStockVO.setOutCount(count);
                        groupByStockVO.setOutAmount(amount);
                    } else {
                        initialCount = initialCount.add(count) ;
                        initialAmount = initialAmount .add(amount) ;
                        groupByStockVO.setInUnitPrice(unitPrice);
                        groupByStockVO.setInCount(count);
                        groupByStockVO.setInAmount(amount);
                    }
                    groupByStockVO.setBalanceCount(initialCount);
                    groupByStockVO.setBalanceAmount(initialAmount);
                    if (initialCount.compareTo(BigDecimal.ZERO)!=0){
                        // unitPrice
                        newInitialUnitPrice = initialAmount.divide(initialCount, ac, BigDecimal.ROUND_HALF_UP);
                        groupByStockVO.setBalanceUnitPrice(newInitialUnitPrice);
                    }else {
                        groupByStockVO.setBalanceUnitPrice(BigDecimal.ZERO);
                    }
                }
            }else {
                groupByStockVOS = Lists.newArrayList();
            }

            InOutStockItemVO inOutStockItem = groupByStockVOS.size()>0 ?groupByStockVOS.get(groupByStockVOS.size() - 1):periodForVO.get(period);
            inOutStockItemVO = new InOutStockItemVO();
            inOutStockItemVO.setStorageTypeName("本期合计");
            // 日期
            inOutStockItemVO.setPeriod(inOutStockItem.getPeriod());
            inOutStockItemVO.setTimes(inOutStockItem.getTimes());

            // 收入数量
            BigDecimal totalInCount = groupByStockVOS
                    .stream()
                    .map(e->e.getInCount()==null?BigDecimal.ZERO:e.getInCount())
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            inOutStockItemVO.setInCount(totalInCount);
            // 收入金额合计
            BigDecimal totalInAmount = groupByStockVOS
                    .stream()
                    .map(e->e.getInAmount()==null?BigDecimal.ZERO:e.getInAmount())
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            inOutStockItemVO.setInAmount(totalInAmount);
            // 合计收入单价
            // unitPrice
            BigDecimal totalInUnitPrice = totalInCount.compareTo(BigDecimal.ZERO)==0?BigDecimal.ZERO:totalInAmount.divide(totalInCount, ac, BigDecimal.ROUND_HALF_UP);
            inOutStockItemVO.setInUnitPrice(totalInUnitPrice);
            // 发出数量
            BigDecimal totalOutCount = groupByStockVOS
                    .stream()
                    .map(e->e.getOutCount()==null?BigDecimal.ZERO:e.getOutCount())
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            inOutStockItemVO.setOutCount(totalOutCount);
            // 发出金额合计
            BigDecimal totalOutAmount = groupByStockVOS
                    .stream()
                    .map(e->e.getOutAmount()==null?BigDecimal.ZERO:e.getOutAmount())
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            inOutStockItemVO.setOutAmount(totalOutAmount);
            // 合计发出单价
            // unitPrice
            BigDecimal totalOutUnitPrice = totalOutCount.compareTo(BigDecimal.ZERO)==0?BigDecimal.ZERO:totalOutAmount.divide(totalOutCount, ac, BigDecimal.ROUND_HALF_UP);
            inOutStockItemVO.setOutUnitPrice(totalOutUnitPrice);
            inOutStockItemVO.setSortNo(2);
            groupByStockVOS.add(inOutStockItemVO);
            totalList.addAll(groupByStockVOS);
        }
        totalList.removeIf(e -> {
            long t = e.getTimes() * 1000;
            return !(t >= statTimeLong && t <= endTimeLong);
        });

        List<InOutStockItemVO> collect = totalList
                .stream()
                .sorted(Comparator.comparing(InOutStockItemVO::getSortNo))
                .sorted(Comparator.comparing(InOutStockItemVO::getTimes))
                .collect(Collectors.toList());
        for (InOutStockItemVO outStockItemVO : collect) {
            int sortNo = outStockItemVO.getSortNo();
            if (sortNo == 2) {
                outStockItemVO.setInOutTime(null);
            }
        }

        if (collect.size() > 0) {
           return Pair.of(collect,Maps.newHashMap());
        }
        return null;
    }

    private List<InOutStockItemVO> getInitDataByStock(Map<String, Object> params) {
        return reportDao.getInitDataByStock(params);
    }

//    private List<InOutStockItemVO> getInitDataForItem(Map<String, Object> params) {
//        return reportDao.getInitDataForItem(params);
//    }

    @Override
    public Pair<List<StockInItemVO>, Map<String, Object>> inStockItemResult(int showTotalInt, int showItemInt, String startTime, String endTime, Long materielType, Long materielId) {
        Map<String, Object> params = Maps.newHashMap();
        boolean showItem = showItemInt == 1;
        boolean showTotal = showTotalInt == 1;

        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("materielId", materielId);
        params.put("materielType", materielType);
        params.put("auditSign", Constant.OK_AUDITED);

        List<StockInItemVO> stockInItemVOS = this.stockInItem(params);
        if (stockInItemVOS.size() > 0) {

            List<StockInItemVO> showList = Lists.newArrayList();

            // 入库数量
            Map<Long, BigDecimal> countMap = stockInItemVOS
                    .stream()
                    .collect(Collectors.toMap(
                            StockInItemVO::getMaterielId
                            , StockInItemVO::getCount
                            , BigDecimal::add));
            // 入库金额
            Map<Long, BigDecimal> amountMap = stockInItemVOS
                    .stream()
                    .collect(Collectors.toMap(
                            StockInItemVO::getMaterielId
                            , StockInItemVO::getAmount
                            , BigDecimal::add));

            // 物料名
            Map<Long, StockInItemVO> materielMap = stockInItemVOS
                    .stream()
                    .collect(Collectors.toMap(
                            StockInItemVO::getMaterielId
                            , v -> v
                            , (v1, v2) -> v1));
            // 获取最大一个时间
            long maxTime = Objects.requireNonNull(DateFormatUtil.getDateByParttern(endTime==null?"2099-12-31":endTime, "yyyy-MM-dd")).getTime();

            maxTime = maxTime + (24 * 3600 * 1000);

            if (showTotal) {
                StockInItemVO stockInItemParam;
                StockInItemVO stockInItemVO;
                for (Long materiel : amountMap.keySet()) {
                    stockInItemParam = materielMap.get(materiel);
                    stockInItemVO = new StockInItemVO();
                    stockInItemVO.setMaterielId(materiel);
                    stockInItemVO.setCount(countMap.get(materiel));
                    stockInItemVO.setAmount(amountMap.get(materiel));
                    stockInItemVO.setInOutTimeParam(new Date(maxTime));
                    // 标记颜色
                    stockInItemVO.setSign(ConstantForReport.COLOUR_END);
                    stockInItemVO.setMaterielName(stockInItemParam.getMaterielName() + ConstantForReport.TOTAL_SUFFIX);
                    stockInItemVO.setSerialNo(stockInItemParam.getSerialNo());
                    stockInItemVO.setSpecification(stockInItemParam.getSpecification());
                    stockInItemVO.setUnitUomName(stockInItemParam.getUnitUomName());
                    // 排序号
                    stockInItemVO.setSortNo(1);

                    showList.add(stockInItemVO);
                }
            }
            if (showItem) {
                showList.addAll(stockInItemVOS);
            }
            List<StockInItemVO> collect = showList.stream()
                    .sorted(Comparator.comparing(StockInItemVO::getSortNo))
                    .sorted(Comparator.comparing(StockInItemVO::getInOutTimeParam))
                    .sorted(Comparator.comparing(StockInItemVO::getMaterielId))
                    .collect(Collectors.toList());

            for (StockInItemVO stockInItemVO : collect) {
                long time = stockInItemVO.getInOutTimeParam().getTime();
                if (time == maxTime) {
                    stockInItemVO.setInOutTime(null);
                }
            }

            // 合计项
            BigDecimal totalCount = countMap
                    .values()
                    .stream()
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            BigDecimal totalAmount = amountMap
                    .values()
                    .stream()
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);

            Map<String, Object> totalResult = Maps.newHashMap();
            totalResult.put("totalCount", totalCount);
            totalResult.put("totalAmount", totalAmount);

            return Pair.of(collect,totalResult);
        }
        return null;
    }

    @Override
    public Pair<List<StockOutItemVO>, Map<String, Object>> outStockItemResult(int showTotalInt, int showItemInt, String startTime, String endTime, Long materielType, Long materielId) {

        Map<String, Object> params = Maps.newHashMap();
        boolean showItem = showItemInt == 1;
        boolean showTotal = showTotalInt == 1;

        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("materielId", materielId);
        params.put("materielType", materielType);
        params.put("auditSign", Constant.OK_AUDITED);

        List<StockOutItemVO> StockOutItemVOS = this.stockOutItem(params);

        if (StockOutItemVOS.size() > 0) {

            List<StockOutItemVO> showList = Lists.newArrayList();

            // 出库数量
            Map<Long, BigDecimal> countMap = StockOutItemVOS
                    .stream()
                    .collect(Collectors.toMap(
                            StockOutItemVO::getMaterielId
                            , StockOutItemVO::getCount
                            , BigDecimal::add));
            // 出库金额
            Map<Long, BigDecimal> amountMap = StockOutItemVOS
                    .stream()
                    .collect(Collectors.toMap(
                            StockOutItemVO::getMaterielId
                            , StockOutItemVO::getAmount
                            , BigDecimal::add));

            // 物料名
            Map<Long, StockOutItemVO> materielMap = StockOutItemVOS
                    .stream()
                    .collect(Collectors.toMap(
                            StockOutItemVO::getMaterielId
                            , v -> v
                            , (v1, v2) -> v1));
            // 获取最大一个时间
            long maxTime = Objects.requireNonNull(DateFormatUtil.getDateByParttern(endTime==null?"2099-12-31":endTime, "yyyy-MM-dd")).getTime();

            maxTime = maxTime + (24 * 3600 * 1000);

            if (showTotal) {
                StockOutItemVO stockOutItemVO;
                StockOutItemVO stockOutItemParam;
                for (Long materiel : amountMap.keySet()) {
                    stockOutItemParam = materielMap.get(materiel);
                    stockOutItemVO = new StockOutItemVO();
                    stockOutItemVO.setCount(countMap.get(materiel));
                    stockOutItemVO.setAmount(amountMap.get(materiel));
                    stockOutItemVO.setOutTimeParam(new Date(maxTime));
                    // 标记颜色
                    stockOutItemVO.setSign(ConstantForReport.COLOUR_END);

                    stockOutItemVO.setMaterielName(stockOutItemParam.getMaterielName() + ConstantForReport.TOTAL_SUFFIX);
                    stockOutItemVO.setMaterielId(materiel);
                    stockOutItemVO.setSerialNo(stockOutItemParam.getSerialNo());
                    stockOutItemVO.setSpecification(stockOutItemParam.getSpecification());
                    stockOutItemVO.setUnitUomName(stockOutItemParam.getUnitUomName());
                    // 排序号
                    stockOutItemVO.setSortNo(1);

                    showList.add(stockOutItemVO);
                }
            }
            if (showItem) {
                showList.addAll(StockOutItemVOS);
            }
            List<StockOutItemVO> collect = showList.stream()
                    .sorted(Comparator.comparing(StockOutItemVO::getSortNo))
                    .sorted(Comparator.comparing(StockOutItemVO::getOutTimeParam))
                    .sorted(Comparator.comparing(StockOutItemVO::getMaterielId))
                    .collect(Collectors.toList());

            // 合计项
            BigDecimal totalCount = countMap
                    .values()
                    .stream()
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            BigDecimal totalAmount = amountMap
                    .values()
                    .stream()
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);

            Map<String, Object> totalResult = Maps.newHashMap();
            totalResult.put("totalCount", totalCount);
            totalResult.put("totalAmount", totalAmount);
            return Pair.of(collect,totalResult);
        }
        return null;
    }

    @Override
    public Pair<List<Map<String,Object>>, Map<String, Object>> pickingSummaryResult(int showTotalInt, int showItemInt, String startTime, String endTime, Long deptId) {
        Map<String, Object> params = Maps.newHashMap();
        boolean showItem = showItemInt == 1;
        boolean showTotal = showTotalInt == 1;
        params.put("deptId", deptId);
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("auditSign", AuditStatusDict.OK_AUDIT.getId());

        List<DictionaryDO> feedingTypes = dictionaryService.listByType(ConstantForMES.FEEDING);
        List<Long> sourceTypes = feedingTypes
                .stream()
                .map(DictionaryDO::getId)
                .collect(Collectors.toList());
        params.put("sourceTypes", sourceTypes);
        List<Map<String, Object>> pickingSummary = this.pickingSummary(params);
        if (pickingSummary.size() > 0) {
            List<Map<String, Object>> showList = Lists.newArrayList();
            // 出库数量
            Map<String, BigDecimal> countMap = pickingSummary
                    .stream()
                    .collect(Collectors.toMap(
                            k -> k.get("productId").toString()
                            , v -> MathUtils.getBigDecimal(v.get("count"))
                            , BigDecimal::add));
            // 出库金额
            Map<String, BigDecimal> amountMap = pickingSummary
                    .stream()
                    .collect(Collectors.toMap(
                            k -> k.get("productId").toString()
                            , v -> MathUtils.getBigDecimal(v.get("amount"))
                            , BigDecimal::add));
            // 产品名
            Map<String, String> productMap = pickingSummary
                    .stream()
                    .collect(Collectors.toMap(
                            k -> k.get("productId").toString()
                            , v -> v.get("productName").toString()
                            , (v1, v2) -> v1));
            if (showTotal) {
                Map<String, Object> map;
                for (String productId : amountMap.keySet()) {
                    map = Maps.newHashMap();
                    map.put("productId", productId);
                    map.put("productName", productMap.get(productId) + ConstantForReport.TOTAL_SUFFIX);
                    map.put("count", countMap.get(productId));
                    map.put("amount", amountMap.get(productId));
                    map.put("sortNo", 1);
                    map.put("sign", ConstantForReport.COLOUR_END);
                    showList.add(map);
                }
            }
            if (showItem) {
                showList.addAll(pickingSummary);
            }
            List<Map<String, Object>> collect = showList.stream()
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("sortNo").toString())))
                    .sorted(Comparator.comparing(e -> Integer.parseInt(e.get("productId").toString())))
                    .collect(Collectors.toList());

            Map<String, Object> totalResult = Maps.newHashMap();
            BigDecimal totalCount = countMap
                    .values()
                    .stream()
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            BigDecimal totalAmount = amountMap
                    .values()
                    .stream()
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            totalResult.put("totalCount", totalCount);
            totalResult.put("totalAmount", totalAmount);
            return Pair.of(collect,totalResult);
        }
        return null;
    }


    @Override
    public void  processingExport(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap, String fileName, List<?> dateList, String chineseName){
        ClassPathResource classPathResource = new ClassPathResource(fileName);
        Map<String,Object> map = Maps.newHashMap();
        map.put("list", dateList);
        TemplateExportParams result = new TemplateExportParams(classPathResource.getPath());
        modelMap.put(TemplateExcelConstants.FILE_NAME, chineseName);
        modelMap.put(TemplateExcelConstants.PARAMS, result);
        modelMap.put(TemplateExcelConstants.MAP_DATA, map);
        PoiBaseView.render(modelMap, request, response,
                TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
    }

    @Override
    public Map<String, Object> ageAnalysis(AgeAnalysisParam pageParam, boolean isExport) {
        Long facilityId = pageParam.getFacilityId();
        String facilityName = "";
        if (facilityId != null) {
            FacilityDO facilityDO = facilityService.get(facilityId);
            facilityName = facilityDO.getName();
        }

        Map<String, Object> map = Maps.newHashMap();
        List<StockAgeSettingDO> stockAgeSettingDOList = stockAgeSettingService.list(map);

        for (int i = stockAgeSettingDOList.size() - 1; i >= 1; i--) {
            StockAgeSettingDO stockAgeSettingDO = stockAgeSettingDOList.get(i);
            Integer day = stockAgeSettingDO.getDay();
            if (day == null){
                continue;
            }
            // 用本次的时间减去上一个的时间得到他们的间隔时间
            stockAgeSettingDO.setDay(day - stockAgeSettingDOList.get(i - 1).getDay());
        }

        Map<String, Long> dateMap;
        List<Map<String, Long>> dateList = Lists.newArrayList();
        Calendar now = Calendar.getInstance();
        for (StockAgeSettingDO stockAgeSettingDO : stockAgeSettingDOList) {
            dateMap = Maps.newHashMap();
            dateMap.put("endTime", now.getTime().getTime());
            now.set(Calendar.DAY_OF_MONTH, now.get(Calendar.DAY_OF_MONTH) - stockAgeSettingDO.getDay());
            dateMap.put("startTime", now.getTime().getTime());
            dateList.add(dateMap);
        }

        List<Map<Long, BigDecimal>> materielIdCollectList = Lists.newArrayList();
        List<StockDO> stockDOList = stockService.listByAgeAnalysisParam(pageParam);
        // 若无库存返回空列表
        if (stockDOList.size() == 0) {
            return R.ok();
        }
        List<Long> materielIdList = stockDOList
                .stream()
                .map(StockDO::getMaterielId)
                .distinct()
                .collect(Collectors.toList());

        Map<Long, BigDecimal> stockCountCollect = stockDOList
                .stream()
                .collect(Collectors.toMap(StockDO::getMaterielId, StockDO::getCount, BigDecimal::add));
        int size = dateList.size();
        boolean isLast = false;
        for (int i = 0; i < size; i++) {
            dateMap = dateList.get(i);
            if (i == size - 1) {
                isLast = true;
            }
            long startTime = dateMap.get("startTime");
            long endTime = dateMap.get("endTime");
            // 时间段id && 物料id
            boolean finalIsLast = isLast;
            Map<Long, BigDecimal> materielIdCollect = stockDOList
                    .stream()
                    .filter(e -> {
                        long time = e.getEnteringTime().getTime();
                        if (finalIsLast) {
                            return time < endTime;
                        }
                        return time >= startTime && time < endTime;
                    })
                    .collect(Collectors.toMap(StockDO::getMaterielId, StockDO::getCount, BigDecimal::add));
            materielIdCollectList.add(materielIdCollect);
        }

        map.put("materielIdList", materielIdList);
        List<Map<String, Object>> materielList = materielService.listForMap(map);
        for (Map<String, Object> materiel : materielList) {
            Long id = Long.parseLong(materiel.get("id").toString());
            for (int i = 0; i < materielIdCollectList.size(); i++) {
                Map<Long, BigDecimal> materielIdCollect = materielIdCollectList.get(i);
                BigDecimal orDefault = materielIdCollect.getOrDefault(id, BigDecimal.ZERO);
                materiel.put(stockAgeSettingDOList.get(i).getName(), orDefault);
            }
            materiel.put("stockCount", stockCountCollect.getOrDefault(id, BigDecimal.ZERO));
            materiel.put("facilityName",facilityName);
        }
        // 导出
        if(isExport){

            exportExcel(materielList,stockAgeSettingDOList,pageParam);
            return null;
        }

        // 合计行
        Map<String,BigDecimal> totalMap = Maps.newHashMap();
        for (StockAgeSettingDO stockAgeSettingDO : stockAgeSettingDOList) {
            String name = stockAgeSettingDO.getName();
            BigDecimal bigDecimal = materielList
                    .stream()
                    .map(k -> TypeUtils.castToBigDecimal(k.getOrDefault(name, BigDecimal.ZERO)))
                    .reduce(BigDecimal::add)
                    .orElse(BigDecimal.ZERO);
            totalMap.put(name, bigDecimal);
        }

        Map<String, Object> result = Maps.newHashMap();
        result.put("data", materielList);
        result.put("total", totalMap);
        return R.ok(result);
    }

    // 导出Excel
    private void exportExcel(List<Map<String, Object>> materielList, List<StockAgeSettingDO> stockAgeSettingDOList, AgeAnalysisParam pageParam) {
        try {
            HttpServletRequest request = pageParam.getRequest();
            HttpServletResponse response = pageParam.getResponse();
            ModelMap modelMap = pageParam.getModelMap();
            List<ExcelExportEntity> colList = new ArrayList<>();

            ExcelExportEntity colEntity;
            List<Map<String, Object>> list = Lists.newArrayList();
            Map<String, Object> valMap = Maps.newHashMap();

            // 表头
            LinkedHashMap<String, String> propertyToLabel = EnumForStockHeader.getPropertyToLabel();
            boolean isFirst = true;
            for (Map.Entry<String, String> stringStringEntry : propertyToLabel.entrySet()) {
                String property = stringStringEntry.getKey();
                colEntity = new ExcelExportEntity(stringStringEntry.getValue(), property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
                if (isFirst) {
                    valMap.put(stringStringEntry.getKey(), "{{$fe:list t." + stringStringEntry.getKey());
                    isFirst = false;
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            // 表中表尾
            StockAgeSettingDO stockAgeSettingDO;
            int size = stockAgeSettingDOList.size();
            for (int i = 0; i < stockAgeSettingDOList.size(); i++) {
                stockAgeSettingDO = stockAgeSettingDOList.get(i);
                String label = stockAgeSettingDO.getName();
                String property = stockAgeSettingDO.getName();
                colEntity = new ExcelExportEntity(label, property);
                colEntity.setNeedMerge(true);
                colList.add(colEntity);
//                if (i == 0) {
//                    valMap.put(property, "{{$fe:list t." + property);
//                    continue;
//                }
                // 最后一个表尾
                if (i == size - 1) {
                    valMap.put(property, "t." + property + "}}");
                    continue;
                }
                valMap.put(property, "t." + property);
            }

            list.add(valMap);
            ExportParams exportParams = new ExportParams();
            exportParams.setSheetName("数据");
            exportParams.setStyle(MyExcelExportStyleConfig.class);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, colList,
                    list);
            String path = request.getSession().getServletContext().getRealPath("/");
            String fileName = path + UUID.randomUUID().toString() + ".xls";
            fileName = fileName.replaceAll("\\\\", "/");
            log.info("临时文件地址: " + fileName);
            FileOutputStream fos = new FileOutputStream(fileName);
            workbook.write(fos);
            fos.close();
//            ClassPathResource classPathResource = new ClassPathResource(fileName);
            Map<String, Object> map = Maps.newHashMap();
            JSONArray format = JSONUtils.format(materielList);
            map.put("list", format);

            File deleteFile = new File(fileName);
            TemplateExportParams result = new TemplateExportParams(deleteFile.getPath());
            modelMap.put(TemplateExcelConstants.FILE_NAME, "库存账龄分析");
            modelMap.put(TemplateExcelConstants.PARAMS, result);
            modelMap.put(TemplateExcelConstants.MAP_DATA, map);
            PoiBaseView.render(modelMap, request, response,
                    TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
            if (deleteFile.exists()) {
                log.info(deleteFile.delete() ? "临时文件已删除" : "临时文件删除失败");
            } else {
                log.error("无临时文件");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public Pair<List<InOutStockSummaryVO>, Map<String, BigDecimal>> inOutSummaryResultNew(int showPeriodTotalInt, int showMaterielTotalInt, int showItemInt, String startTimeParam, String endTimeParam, Long materielType, Long materielId) {
        Date startPeriod = DateFormatUtil.getDateByParttern(startTimeParam, DateFormatUtil.DATE_PATTERN_YMD);

        Date endPeriod = DateFormatUtil.getDateByParttern(endTimeParam, DateFormatUtil.DATE_PATTERN_YMD);
        if (endPeriod == null || startPeriod == null) {
            return null;
        }
        List<String> periodList = stockStartService.getPeriodList(startPeriod,endPeriod);
        String startTime = DatesUtil.getSupportBeginDayOfMonth(startPeriod);
        String endTime = DatesUtil.getSupportEndDayOfMonth(endPeriod);

        Map<String, Object> params = Maps.newHashMap();
        boolean showItem = showItemInt == 1;
        boolean showMaterielTotal = showMaterielTotalInt == 1;
        boolean showPeriodTotal = showPeriodTotalInt == 1;
        List<InOutStockSummaryVO> showList = Lists.newArrayList();
        params.put("materielId", materielId);
        params.put("materielType", materielType);
        params.put("auditSign", AuditStatusDict.OK_AUDIT.getId());
        // 检查是否存在数据不存在则直接弹出
        boolean isEmptyData = checkData(startTime,endTime,params);
        if (isEmptyData){
            return null;
        }

        params.put("deadline", startTime);

        // 截至时间 计算查询开始前期初数据(总计)
        List<InOutStockSummaryVO> initDataByPeriod = this.getInitDataByStockSummary(params);
        // 截至时间 计算查询开始前期初数据(按物料)
        params.put("materielIdGroup", true);
        List<InOutStockSummaryVO> initDataByMateriel = this.getInitDataByStockSummary(params);
        params.remove("materielIdGroup");
        // 截至时间 计算查询开始前期初数据(按物料批次)
        params.put("batchGroup", true);
        List<InOutStockSummaryVO> initDataByBatch = this.getInitDataByStockSummary(params);
        params.remove("batchGroup");

        // 查询明细
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.remove("deadline");
        // 按期间
        params.put("period", true);
        List<InOutStockSummaryVO> itemDataByPeriod = this.getInitDataByStockSummary(params);
        params.remove("period");
        // 按期间与物料
        params.put("periodAndMaterielIdGroup", true);
        List<InOutStockSummaryVO> itemDataByMateriel = this.getInitDataByStockSummary(params);
        params.remove("periodAndMaterielIdGroup");
        // 按批次与期间
        params.put("periodAndBatchGroup", true);
        List<InOutStockSummaryVO> itemDataByBatch = this.getInitDataByStockSummary(params);
        params.remove("periodAndBatchGroup");

        // 整合期间总计
        this.handlePeriodData(initDataByPeriod,itemDataByPeriod,periodList,showList);
        Map<String,BigDecimal> totalResult = this.getSummaryTotalResult(showList);

        if (!showPeriodTotal){
            showList.clear();
        }
        // 整合物料汇总
        if (showMaterielTotal) {
            this.handleMaterielData(initDataByMateriel,itemDataByMateriel,periodList,0,showList);
        }
        // 整合物料与批次汇总
        if (showItem){
            this.handleMaterielBatchData(initDataByBatch,itemDataByBatch,periodList,0,showList);
        }


        List<Long> materielIdList = showList.stream().map(InOutStockSummaryVO::getMaterielId).distinct().collect(Collectors.toList());
        Map<String,Object> param = Maps.newHashMap();
        param.put("materielIdList",materielIdList);
        List<MaterielDO> materielList = materielService.list(param);
        Map<Long, MaterielDO> materielDOMap = materielList.stream().collect(Collectors.toMap(MaterielDO::getId, e -> e));
        showList.forEach(e->{
            Long m = e.getMaterielId();
            MaterielDO materielDO = materielDOMap.get(m);
            if (materielDO != null) {
                boolean isMaterielTotal = e.getSortNo()==1;
                e.setMaterielName(materielDO.getName()+(isMaterielTotal?ConstantForReport.TOTAL_SUFFIX:""));
                e.setMaterielSerialNo(materielDO.getSerialNo());
                e.setSpecification(materielDO.getSpecification());
                e.setUnitUomName(materielDO.getUnitUomName());
                e.setMaterielTypeName(materielDO.getTypeName());
            }
        });

        List<InOutStockSummaryVO> collect = showList.stream()
                .sorted(Comparator.comparing(InOutStockSummaryVO::getSortNo))
                .sorted(Comparator.comparing(InOutStockSummaryVO::getMaterielId))
                .sorted(Comparator.comparing(InOutStockSummaryVO::getTimes))
                .collect(Collectors.toList());


        return Pair.of(collect, totalResult);

    }

    private Map<String, BigDecimal> getSummaryTotalResult(List<InOutStockSummaryVO> showList) {
        Map<String,BigDecimal> totalResult = Maps.newHashMap();
        List<InOutStockSummaryVO> computeTotal = ListUtils.deepCopy(showList);
        InOutStockSummaryVO total = computeTotal.stream().reduce((e1, e2) -> {
            e1.setInitialCount(e1.getInitialCount().add(e2.getInitialCount()));
            e1.setInitialAmount(e1.getInitialAmount().add(e2.getInitialAmount()));
            e1.setInCount(e1.getInCount().add(e2.getInCount()));
            e1.setInAmount(e1.getInAmount().add(e2.getInAmount()));
            e1.setOutCount(e1.getOutCount().add(e2.getOutCount()));
            e1.setOutAmount(e1.getOutAmount().add(e2.getOutAmount()));
            e1.setFinalAmount(e1.getFinalAmount().add(e2.getFinalAmount()));
            e1.setFinalCount(e1.getFinalCount().add(e2.getFinalCount()));
            return e1;
        }).orElse(new InOutStockSummaryVO());
        totalResult.put("totalInitialCount",total.getInitialCount());
        totalResult.put("totalInitialAmount",total.getInitialAmount());
        totalResult.put("totalInCount",total.getInCount());
        totalResult.put("totalInAmount",total.getInAmount());
        totalResult.put("totalOutCount",total.getOutCount());
        totalResult.put("totalOutAmount",total.getOutAmount());
        totalResult.put("totalFinalCount",total.getFinalCount());
        totalResult.put("totalFinalAmount",total.getFinalAmount());
        return totalResult;
    }

    private void handleMaterielBatchData(List<InOutStockSummaryVO> initDataByBatch, List<InOutStockSummaryVO> itemDataByBatch, List<String> periodList, int i, List<InOutStockSummaryVO> showList) {
        if (i == periodList.size()) {
            return;
        }
        // 若结余数量 结余金额为0则不往下结余
        this.removeInitDataIsEmptyData(initDataByBatch);

        String period = periodList.get(i);
        // 上一期结余物料
        // 若上一期没有结余
        if (initDataByBatch.size() == 0) {
            List<InOutStockSummaryVO> thisPeriodList = itemDataByBatch.stream().filter(e -> Objects.equals(period, e.getPeriod())).collect(Collectors.toList());
            if (thisPeriodList.size() > 0) {
                thisPeriodList.forEach(e -> {
                    e.setInitialCount(BigDecimal.ZERO);
                    e.setInitialAmount(BigDecimal.ZERO);
                    e.setSign(0);
                    e.setSortNo(0);
                    e.setTimes(DatesUtil.getSupportEndDayOfMonth(period + "-01 00:00:00").getTime() / 1000);
                });
                showList.addAll(thisPeriodList);
                itemDataByBatch.removeAll(thisPeriodList);
            }
            i++;
            this.handleMaterielBatchData(thisPeriodList, itemDataByBatch, periodList, i, showList);
            return;
        }
        // 本期物料
        List<InOutStockSummaryVO> thisPeriodList = itemDataByBatch.stream().filter(e -> Objects.equals(period, e.getPeriod())).collect(Collectors.toList());
        itemDataByBatch.removeAll(thisPeriodList);
        List<String> materielAndBatchList = Lists.newArrayList();
        for (InOutStockSummaryVO init : initDataByBatch) {
            boolean notExist = true;
            Long materielId = init.getMaterielId();
            String initBatch = init.getBatch();
            for (InOutStockSummaryVO thisP : thisPeriodList) {
                if (Objects.equals(materielId, thisP.getMaterielId()) && (initBatch == null || Objects.equals(initBatch, thisP.getBatch()))) {
                    notExist = false;
                    thisP.setInitialCount(init.getFinalCount());
                    thisP.setInitialAmount(init.getFinalAmount());
                    thisP.setFinalCount(thisP.getFinalCount().add(thisP.getInitialCount()));
                    thisP.setFinalAmount(thisP.getFinalAmount().add(thisP.getInitialAmount()));
                    break;
                }
            }
            if (notExist) {
                materielAndBatchList.add(materielId+initBatch);
            }
        }
        if (materielAndBatchList.size() > 0) {
            List<InOutStockSummaryVO> initList = initDataByBatch.stream().filter(e -> materielAndBatchList.contains(e.getMaterielId() + e.getBatch())).collect(Collectors.toList());
            InOutStockSummaryVO init;
            for (InOutStockSummaryVO inOutStockSummaryVO : initList) {
                init = new InOutStockSummaryVO();
                BeanUtils.copyProperties(inOutStockSummaryVO, init);
                init.setPeriod(period);
                init.setInitialCount(init.getFinalCount());
                init.setInitialAmount(init.getFinalAmount());

                init.setInAmount(BigDecimal.ZERO);
                init.setInCount(BigDecimal.ZERO);
                init.setOutAmount(BigDecimal.ZERO);
                init.setOutCount(BigDecimal.ZERO);
                thisPeriodList.add(init);
            }
        }
        thisPeriodList.forEach(e -> {
            e.setSign(0);
            e.setSortNo(0);
            // 上期没有本期存在的期初赋0
            // 上期没有本期存在的期初赋0
            if (e.getInitialAmount() == null) {
                e.setInitialAmount(BigDecimal.ZERO);
            }
            if (e.getInitialCount() == null) {
                e.setInitialCount(BigDecimal.ZERO);
            }
            e.setTimes(DatesUtil.getSupportEndDayOfMonth(period + "-01 00:00:00").getTime() / 1000);
        });
        i++;
        showList.addAll(thisPeriodList);
        this.handleMaterielBatchData(thisPeriodList, itemDataByBatch, periodList, i, showList);
    }

    private void handleMaterielData(List<InOutStockSummaryVO> initDataByMateriel, List<InOutStockSummaryVO> itemDataByMateriel, List<String> periodList, int i, List<InOutStockSummaryVO> showList) {
        if (i == periodList.size()) {
            return;
        }
        // 若结余数量 结余金额为0则不往下结余
        this.removeInitDataIsEmptyData(initDataByMateriel);

        String period = periodList.get(i);
        // 上一期结余物料
        // 若上一期没有结余
        if (initDataByMateriel.size() == 0) {
            List<InOutStockSummaryVO> thisPeriodList = itemDataByMateriel.stream().filter(e -> Objects.equals(period, e.getPeriod())).collect(Collectors.toList());
            if (thisPeriodList.size() > 0) {
                thisPeriodList.forEach(e -> {
                    e.setInitialCount(BigDecimal.ZERO);
                    e.setInitialAmount(BigDecimal.ZERO);
                    e.setSign(1);
                    e.setSortNo(1);
                    e.setBatch(null);
                    e.setTimes(DatesUtil.getSupportEndDayOfMonth(period + "-01 00:00:00").getTime() / 1000);
                });
                showList.addAll(thisPeriodList);
                itemDataByMateriel.removeAll(thisPeriodList);
            }
            i++;
            this.handleMaterielData(thisPeriodList, itemDataByMateriel, periodList, i, showList);
            return;
        }
        // 本期物料
        List<InOutStockSummaryVO> thisPeriodList = itemDataByMateriel.stream().filter(e -> Objects.equals(period, e.getPeriod())).collect(Collectors.toList());
        itemDataByMateriel.removeAll(thisPeriodList);
        List<Long> materielIdList = Lists.newArrayList();
        for (InOutStockSummaryVO init : initDataByMateriel) {
            boolean notExist = true;
            Long materielId = init.getMaterielId();
            for (InOutStockSummaryVO thisP : thisPeriodList) {
                if (Objects.equals(materielId, thisP.getMaterielId())) {
                    notExist = false;
                    thisP.setInitialCount(init.getFinalCount());
                    thisP.setInitialAmount(init.getFinalAmount());
                    thisP.setFinalCount(thisP.getFinalCount().add(thisP.getInitialCount()));
                    thisP.setFinalAmount(thisP.getFinalAmount().add(thisP.getInitialAmount()));
                    break;
                }
            }
            if (notExist) {
                materielIdList.add(materielId);
            }
        }
        if (materielIdList.size() > 0) {
            List<InOutStockSummaryVO> initList = initDataByMateriel.stream().filter(e -> materielIdList.contains(e.getMaterielId())).collect(Collectors.toList());
            InOutStockSummaryVO init;
            for (InOutStockSummaryVO inOutStockSummaryVO : initList) {
                init = new InOutStockSummaryVO();
                BeanUtils.copyProperties(inOutStockSummaryVO, init);
                init.setPeriod(period);
                init.setInitialCount(init.getFinalCount());
                init.setInitialAmount(init.getFinalAmount());

                init.setInAmount(BigDecimal.ZERO);
                init.setInCount(BigDecimal.ZERO);
                init.setOutAmount(BigDecimal.ZERO);
                init.setOutCount(BigDecimal.ZERO);

                thisPeriodList.add(init);
            }
        }
        thisPeriodList.forEach(e -> {
            e.setSign(1);
            e.setSortNo(1);
            // 上期没有本期存在的期初赋0
            if (e.getInitialAmount() == null) {
                e.setInitialAmount(BigDecimal.ZERO);
            }
            if (e.getInitialCount() == null) {
                e.setInitialCount(BigDecimal.ZERO);
            }

            e.setBatch(null);
            e.setTimes(DatesUtil.getSupportEndDayOfMonth(period + "-01 00:00:00").getTime() / 1000);
        });
        i++;
        showList.addAll(thisPeriodList);
        this.handleMaterielData(thisPeriodList, itemDataByMateriel, periodList, i, showList);
    }

    private void removeInitDataIsEmptyData(List<InOutStockSummaryVO> initData) {
        initData.removeIf(e -> e.getFinalAmount().compareTo(BigDecimal.ZERO) == 0 && e.getFinalCount().compareTo(BigDecimal.ZERO) == 0);
    }

    private void handlePeriodData(List<InOutStockSummaryVO> initDataByPeriod, List<InOutStockSummaryVO> itemDataByPeriod, List<String> periodList,List<InOutStockSummaryVO> showList) {
        initDataByPeriod.removeIf(Objects::isNull);
        // 若结余数量 结余金额为0则不往下结余
        this.removeInitDataIsEmptyData(initDataByPeriod);

        BigDecimal initAmountTotal = BigDecimal.ZERO;
        BigDecimal initCountTotal = BigDecimal.ZERO;
        if (periodList.size() != itemDataByPeriod.size()) {
            List<String> periodListCopy = ListUtils.deepCopy(periodList);
            long firstPeriod = itemDataByPeriod.get(0).getTimes();
            periodListCopy.removeAll(itemDataByPeriod.stream().map(InOutStockSummaryVO::getPeriod).collect(Collectors.toList()));
            InOutStockSummaryVO inOutStockSummaryVO;
            for (String s : periodListCopy) {
                // 过滤空期间
                long thisPeriod = DatesUtil.getSupportEndDayOfMonth(s + "-01 00:00:00").getTime() / 1000;
                if (thisPeriod<firstPeriod){
                    continue;
                }

                inOutStockSummaryVO = new InOutStockSummaryVO();
                inOutStockSummaryVO.setPeriod(s);
                inOutStockSummaryVO.setInitialAmount(BigDecimal.ZERO);
                inOutStockSummaryVO.setInitialCount(BigDecimal.ZERO);
                inOutStockSummaryVO.setInCount(BigDecimal.ZERO);
                inOutStockSummaryVO.setInAmount(BigDecimal.ZERO);
                inOutStockSummaryVO.setOutAmount(BigDecimal.ZERO);
                inOutStockSummaryVO.setOutCount(BigDecimal.ZERO);
                inOutStockSummaryVO.setFinalCount(BigDecimal.ZERO);
                inOutStockSummaryVO.setFinalAmount(BigDecimal.ZERO);
                inOutStockSummaryVO.setTimes(DatesUtil.getSupportEndDayOfMonth(s + "-01 00:00:00").getTime() / 1000);
                itemDataByPeriod.add(inOutStockSummaryVO);
            }
        }


        if (initDataByPeriod.size() > 0) {
            initAmountTotal = initDataByPeriod.get(0).getFinalAmount();
            initCountTotal = initDataByPeriod.get(0).getFinalCount();
        }
        itemDataByPeriod.sort(Comparator.comparing(InOutStockSummaryVO::getTimes));
        for (InOutStockSummaryVO inOutStockSummaryVO : itemDataByPeriod) {
            inOutStockSummaryVO.setInitialAmount(initAmountTotal);
            inOutStockSummaryVO.setInitialCount(initCountTotal);

            BigDecimal finalAmount = inOutStockSummaryVO.getFinalAmount();
            BigDecimal finalCount = inOutStockSummaryVO.getFinalCount();

            // 本月结余赋给下月期初
            initAmountTotal = initAmountTotal.add(finalAmount);
            initCountTotal = initCountTotal.add(finalCount);
            // 本月结余赋值
            inOutStockSummaryVO.setFinalAmount(initAmountTotal);
            inOutStockSummaryVO.setFinalCount(initCountTotal);

            // 过滤空期间
            if (
                    inOutStockSummaryVO.getInitialCount().compareTo(BigDecimal.ZERO) == 0
                    && inOutStockSummaryVO.getInitialAmount().compareTo(BigDecimal.ZERO) == 0
                    && inOutStockSummaryVO.getFinalCount().compareTo(BigDecimal.ZERO) == 0
                    && inOutStockSummaryVO.getFinalAmount().compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }

            // 设置一些字段为空 以及设置一些排序
            String period = inOutStockSummaryVO.getPeriod();
            inOutStockSummaryVO.setSign(ConstantForReport.COLOUR_END);
            inOutStockSummaryVO.setMaterielId(Long.MAX_VALUE);
            inOutStockSummaryVO.setTimes(DatesUtil.getSupportEndDayOfMonth(period + "-01 00:00:00").getTime() / 1000);
            inOutStockSummaryVO.setSortNo(2);
            inOutStockSummaryVO.setBatch(null);
            inOutStockSummaryVO.setPeriod(inOutStockSummaryVO.getPeriod() + ConstantForReport.TOTAL_SUFFIX);

            showList.add(inOutStockSummaryVO);
        }
    }

    private boolean checkData(String startTime, String endTime, Map<String, Object> params) {
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("findFirst", true);
        List<InOutStockSummaryVO> itemDataByMateriel = this.getInitDataByStockSummary(params);
        itemDataByMateriel.removeIf(Objects::isNull);
        if (itemDataByMateriel.size() == 0) {
            return true;
        }
        params.remove("startTime");
        params.remove("endTime");
        params.remove("findFirst");
        return false;
    }

    private List<InOutStockSummaryVO> getInitDataByStockSummary(Map<String, Object> params) {
        return reportDao.getInitDataByStockSummary(params);
    }


    @Override
    public Pair<List<InOutStockSummaryVO>, Map<String, BigDecimal>> inOutSummaryResultForItem(int showPeriodTotalInt, int showMaterielTotalInt, int showItemInt, String startTimeParam, String endTimeParam, Long materielType, Long materielId) {
        Date startPeriod = DateFormatUtil.getDateByParttern(startTimeParam, DateFormatUtil.DATE_PATTERN_YMD);

        Date endPeriod = DateFormatUtil.getDateByParttern(endTimeParam, DateFormatUtil.DATE_PATTERN_YMD);
        if (endPeriod == null || startPeriod == null) {
            return null;
        }

        Map<String, Object> params = Maps.newHashMap();
//        boolean showItem = showItemInt == 1;
        boolean showMaterielTotal = showMaterielTotalInt == 1;
        List<InOutStockSummaryVO> showList = Lists.newArrayList();
        params.put("materielId", materielId);
        params.put("materielType", materielType);
        params.put("auditSign", AuditStatusDict.OK_AUDIT.getId());
        // 检查是否存在数据不存在则直接弹出
        boolean isEmptyData = checkData(null, endTimeParam,params);
        if (isEmptyData){
            return null;
        }
        params.put("deadline", startTimeParam);

        // 截至时间 计算查询开始前期初数据(按物料)
        params.put("materielIdGroup", true);
        List<InOutStockSummaryVO> initDataByMateriel = this.getInitDataByStockSummary(params);
        params.remove("materielIdGroup");
        // 截至时间 计算查询开始前期初数据(按物料批次)
//        params.put("batchGroup", true);
//        List<InOutStockSummaryVO> initDataByBatch = this.getInitDataByStockSummary(params);
//        params.remove("batchGroup");

        // 查询明细
        params.put("startTime", startTimeParam);
        params.put("endTime", endTimeParam);
        params.remove("deadline");
        // 按物料
        params.put("materielIdGroup", true);
        List<InOutStockSummaryVO> itemDataByMateriel = this.getInitDataByStockSummary(params);
        params.remove("materielIdGroup");
        // 按批次
//        params.put("batchGroup", true);
//        List<InOutStockSummaryVO> itemDataByBatch = this.getInitDataByStockSummary(params);

        this.handleMaterielData(initDataByMateriel, itemDataByMateriel);
        Map<String, BigDecimal> totalResult = this.getSummaryTotalResult(itemDataByMateriel);
        // 整合物料汇总
        if (showMaterielTotal) {
            showList.addAll(itemDataByMateriel);
        }

        // 整合物料与批次汇总
//        if (showItem){
//            this.handleMaterielBatchData(initDataByBatch,itemDataByBatch,showList);
//        }


        List<Long> materielIdList = showList.stream().map(InOutStockSummaryVO::getMaterielId).distinct().collect(Collectors.toList());
        Map<String,Object> param = Maps.newHashMap();
        param.put("materielIdList",materielIdList);
        List<MaterielDO> materielList = materielService.list(param);
        Map<Long, MaterielDO> materielDOMap = materielList.stream().collect(Collectors.toMap(MaterielDO::getId, e -> e));
        showList.forEach(e->{
            Long m = e.getMaterielId();
            MaterielDO materielDO = materielDOMap.get(m);
            if (materielDO != null) {
//                boolean isMaterielTotal = e.getSortNo()==1;
//                e.setMaterielName(materielDO.getName()+(isMaterielTotal?ConstantForReport.TOTAL_SUFFIX:""));
                e.setMaterielName(materielDO.getName());
                e.setMaterielSerialNo(materielDO.getSerialNo());
                e.setSpecification(materielDO.getSpecification());
                e.setUnitUomName(materielDO.getUnitUomName());
                e.setMaterielTypeName(materielDO.getTypeName());
            }
        });
        if (showList.size() == 0) {
            return null;
        }
        List<InOutStockSummaryVO> collect = showList.stream()
//                .sorted(Comparator.comparing(InOutStockSummaryVO::getSortNo))
                .sorted(Comparator.comparing(InOutStockSummaryVO::getMaterielId))
                .collect(Collectors.toList());

        return Pair.of(collect, totalResult);

    }

    private void handleMaterielData(List<InOutStockSummaryVO> initDataByMateriel, List<InOutStockSummaryVO> itemDataByMateriel) {

        // 若结余数量 结余金额为0则不往下结余
        // 上一期结余物料
        // 若上一期没有结余
        // 本期物料
        List<Long> materielIdList = Lists.newArrayList();
        for (InOutStockSummaryVO init : initDataByMateriel) {
            boolean notExist = true;
            Long materielId = init.getMaterielId();
            for (InOutStockSummaryVO thisP : itemDataByMateriel) {
                if (Objects.equals(materielId, thisP.getMaterielId())) {
                    notExist = false;
                    thisP.setInitialCount(init.getFinalCount());
                    thisP.setInitialAmount(init.getFinalAmount());
                    thisP.setFinalCount(thisP.getFinalCount().add(thisP.getInitialCount()));
                    thisP.setFinalAmount(thisP.getFinalAmount().add(thisP.getInitialAmount()));
                    break;
                }
            }
            if (notExist) {
                materielIdList.add(materielId);
            }
        }

        if (materielIdList.size() > 0) {
            List<InOutStockSummaryVO> initList = initDataByMateriel.stream().filter(e -> materielIdList.contains(e.getMaterielId())).collect(Collectors.toList());
            InOutStockSummaryVO init;
            for (InOutStockSummaryVO inOutStockSummaryVO : initList) {
                if (inOutStockSummaryVO.getFinalCount().compareTo(BigDecimal.ZERO) == 0
                        && inOutStockSummaryVO.getFinalAmount().compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                init = new InOutStockSummaryVO();
                BeanUtils.copyProperties(inOutStockSummaryVO, init);
                init.setInitialCount(init.getFinalCount());
                init.setInitialAmount(init.getFinalAmount());

                init.setInAmount(BigDecimal.ZERO);
                init.setInCount(BigDecimal.ZERO);
                init.setOutAmount(BigDecimal.ZERO);
                init.setOutCount(BigDecimal.ZERO);

                itemDataByMateriel.add(init);
            }
        }
        itemDataByMateriel.forEach(e -> {
            e.setSign(0);
            e.setSortNo(0);
            // 上期没有本期存在的期初赋0
            if (e.getInitialAmount() == null) {
                e.setInitialAmount(BigDecimal.ZERO);
            }
            if (e.getInitialCount() == null) {
                e.setInitialCount(BigDecimal.ZERO);
            }

            e.setBatch(null);
        });
    }
    private void handleMaterielBatchData(List<InOutStockSummaryVO> initDataByBatch, List<InOutStockSummaryVO> itemDataByBatch, List<InOutStockSummaryVO> showList) {

        // 若结余数量 结余金额为0则不往下结余
        // 上一期结余物料
        // 若上一期没有结余
        // 本期物料
        List<Long> materielIdList = Lists.newArrayList();
        for (InOutStockSummaryVO init : initDataByBatch) {
            boolean notExist = true;
            Long materielId = init.getMaterielId();
            for (InOutStockSummaryVO thisP : itemDataByBatch) {
                if (Objects.equals(materielId, thisP.getMaterielId())) {
                    notExist = false;
                    thisP.setInitialCount(init.getFinalCount());
                    thisP.setInitialAmount(init.getFinalAmount());
                    thisP.setFinalCount(thisP.getFinalCount().add(thisP.getInitialCount()));
                    thisP.setFinalAmount(thisP.getFinalAmount().add(thisP.getInitialAmount()));
                    break;
                }
            }
            if (notExist) {
                materielIdList.add(materielId);
            }
        }

        if (materielIdList.size() > 0) {
            List<InOutStockSummaryVO> initList = itemDataByBatch.stream().filter(e -> materielIdList.contains(e.getMaterielId())).collect(Collectors.toList());
            InOutStockSummaryVO init;
            for (InOutStockSummaryVO inOutStockSummaryVO : initList) {
                init = new InOutStockSummaryVO();
                BeanUtils.copyProperties(inOutStockSummaryVO, init);
                init.setInitialCount(init.getFinalCount());
                init.setInitialAmount(init.getFinalAmount());

                init.setInAmount(BigDecimal.ZERO);
                init.setInCount(BigDecimal.ZERO);
                init.setOutAmount(BigDecimal.ZERO);
                init.setOutCount(BigDecimal.ZERO);

                itemDataByBatch.add(init);
            }
        }
        itemDataByBatch.forEach(e -> {
            e.setSign(0);
            e.setSortNo(0);
            // 上期没有本期存在的期初赋0
            if (e.getInitialAmount() == null) {
                e.setInitialAmount(BigDecimal.ZERO);
            }
            if (e.getInitialCount() == null) {
                e.setInitialCount(BigDecimal.ZERO);
            }

        });

        showList.addAll(itemDataByBatch);
    }
    
    
    
}
